/*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#define PLUGIN_NAME		"Rocket Jump"
#define PLUGIN_AUTHOR		"Blaize"
#define PLUGIN_DESC		"make a rocket jump with grenade launcher"
#define PLUGIN_VERSION		"0.1"
#define PLUGIN_FILENAME		"l4d2_rocketjump"

#define TEAM_SPECTATORS		1
#define TEAM_SURVIVORS		2
#define TEAM_INFECTED		3
#define CVAR_FLAGS 		FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_NOTIFY

#include <sourcemod>
#include <sdktools>
#include <sdkhooks>

#include "macros.sp"
#include "helpers.sp"

new Handle:cvar_rocketMult_power = INVALID_HANDLE;
new Handle:cvar_rocketError_correction = INVALID_HANDLE;
new Handle:cvar_rocketBonus_fall = INVALID_HANDLE;
new Handle:cvar_rocketBonus_high = INVALID_HANDLE;

public OnPluginStart()
{
	cvar_rocketMult_power = CreateConVar("l4d2_rocketjump_mult_power", "300", " How much Force multiplier is applied to the target", CVAR_FLAGS);
	cvar_rocketError_correction = CreateConVar("l4d2_rocketjump_correction", "50", "Y position margin between explosion and player", CVAR_FLAGS);
	cvar_rocketBonus_fall = CreateConVar("l4d2_rocketjump_bonus_fall", "315", "Velocity divided by this. Less it is, more the player is ejected. Calculate the boost value", CVAR_FLAGS);
	cvar_rocketBonus_high = CreateConVar("l4d2_rocketjump_bonus_high", "100", "How high the player is ejected when falling (to make long jump with bonus fall) this value is multiplied by boost", CVAR_FLAGS);
	AutoExecConfig(true, PLUGIN_FILENAME);
}

public OnClientPutInServer(client)
{
	SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
}

public OnClientDisconnect(client)
{
	SDKUnhook(client, SDKHook_OnTakeDamage, OnTakeDamage);
}

/* entity : id of player who take damage
   attacker : weapon which does damage
*/
public Action:OnTakeDamage(entity, &inflictor, &attacker, &Float:damage, &damageType, &weapon, const Float:damageForce[3], const Float:damagePosition[3])
{

	if(IsValidSurvivorAlive(entity) && IsValidEntity(attacker) && IsValidEdict(attacker))
	{

		decl String:wep[32];
		GetEdictClassname(attacker, wep, sizeof(wep));

		if(strcmp(wep, "grenade_launcher_projectile") == 0) //shoot with GL
		{
			decl Float:player_pos[3];
			GetClientAbsOrigin(entity, player_pos);

			//player - projectil == projectile ----> player
			decl Float:vec[3];

			//calculate if player shoot just on his feet
			new Float:dist_from_ground = player_pos[2] - damagePosition[2];
			new Float:correction = GetConVarFloat(cvar_rocketError_correction);

			/* add a margin for small difference of high */
			if(dist_from_ground >= -correction && dist_from_ground <= correction)
			{
				/*simulate player in air*/
				player_pos[2] -= dist_from_ground; //set to 0
				player_pos[2] += correction;
			}

			MakeVectorFromPoints(damagePosition, player_pos, vec);

			decl Float:norm_vec[3];
			NormalizeVector(vec, norm_vec);

			//add force to this vector
			ScaleVector(norm_vec, GetConVarFloat(cvar_rocketMult_power));
			
			//get velocity from player
			decl Float:velocity[3];
			GetEntPropVector(entity, Prop_Data, "m_vecVelocity", velocity);
						
			if(velocity[2] < 0)
			{

				/* get a positive vector for velocity when player fall */
				new Float:zvel = -velocity[2];

				/*give a litle boost if player fall */
				new Float:boost = (zvel / GetConVarFloat(cvar_rocketBonus_fall)); 
				velocity[0] *= boost;
				velocity[1] *= boost;
				velocity[2] = GetConVarFloat(cvar_rocketBonus_high) * boost;

			}

			//addin velocity to the final vector
			decl Float:result[3];
			AddVectors(norm_vec, velocity, result);

			//do rocket jump
			TeleportEntity(entity, NULL_VECTOR, NULL_VECTOR, result);

			//cancel damage
			damage = 0.0;
			return Plugin_Changed;
		}

	}

	return Plugin_Continue;
}

